use std::env;
use anyhow::Error;
use chrono::Utc;
use serde::{Serialize, Deserialize};
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
use crate::utils::error::AppError; // 自定义错误类型（示例）

// JWT 生成/验证
// https://crates.io/crates/jsonwebtoken
// cargo add jsonwebtoken

// JWT 的载荷 (Payload) 数据
// 定义JWT的claims(声明)结构体
// 这些字段会被编码到token中
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,     // 主题(通常是用户ID)
    pub exp: usize,      // 过期时间（Unix 时间戳）
    pub iat: usize,      // 签发时间
    pub custom_data: String, // 自定义字段（可选）
}

impl Claims {
    /// 创建新的 Claims（自动设置签发时间和过期时间）
    pub fn new(user_id: &str, custom_data: &str, expires_in_hours: i64) -> Self {
        let now = Utc::now();
        let exp = now + chrono::Duration::hours(expires_in_hours);

        Self {
            sub: user_id.to_string(),
            exp: exp.timestamp() as usize,
            iat: now.timestamp() as usize,
            custom_data: custom_data.to_string(),
        }
    }
}

/// JWT 配置（密钥和算法）
pub struct JwtConfig {
    pub secret: String,         // JWT加密密钥 - 实际应用中应从安全配置中获取
    pub algorithm: Algorithm,   // 算法
}

impl Default for JwtConfig {
    fn default() -> Self {
        // Load environment variables from .env file.
        // Fails if .env file not found, not readable or invalid.
        dotenvy::dotenv()?;

        for (key, value) in env::vars() {
            println!("{key}: {value}");
        }
        Self {
            secret: "your-secret-key".to_string(), // 应从环境变量读取
            algorithm: Algorithm::HS256, // 推荐 HS256 或 RS256
        }
    }
}

/// 生成 JWT Token
pub fn generate_token(claims: &Claims, config: &JwtConfig) -> Result<String, Error> {
    Ok(encode(
        &Header::new(config.algorithm), // 使用指定算法
        claims,
        &EncodingKey::from_secret(config.secret.as_ref()), // 密钥
    )?)
}

/// 验证并解析 JWT Token
pub fn verify_token(token: &str, config: &JwtConfig) -> Result<Claims, Error> {
    let mut validation = Validation::new(config.algorithm);
    validation.validate_exp = true; // 检查过期时间，默认为 true

    Ok(decode(
        token,
        &DecodingKey::from_secret(config.secret.as_ref()),
        &validation,
    )?.claims)
}